home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / JFC.bin / BoxView.java < prev    next >
Text File  |  1998-06-30  |  21KB  |  717 lines

  1. /*
  2.  * @(#)BoxView.java    1.16 98/04/09
  3.  * 
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  */
  20. package com.sun.java.swing.text;
  21.  
  22. import java.io.PrintStream;
  23. import java.util.Vector;
  24. import java.awt.*;
  25. import com.sun.java.swing.event.DocumentEvent;
  26.  
  27. /**
  28.  * A view of a text model that arranges its children into a
  29.  * box.  It might be useful to represent something like a 
  30.  * collection of lines, paragraphs, list items, chunks of text,
  31.  * etc.  The box is somewhat like that found in TeX where
  32.  * there is alignment of the children, flexibility of the
  33.  * children is considered, etc.
  34.  *
  35.  * @author  Timothy Prinzing
  36.  * @version 1.16 04/09/98
  37.  */
  38. public class BoxView extends CompositeView {
  39.  
  40.     /**
  41.      * Constructs a BoxView.
  42.      *
  43.      * @param elem the element this view is responsible for
  44.      * @param axis either View.X_AXIS or View.Y_AXIS
  45.      */
  46.     public BoxView(Element elem, int axis) {
  47.     super(elem);
  48.     this.axis = axis;
  49.     }
  50.  
  51.     /**
  52.      * Paints a child.  By default
  53.      * that is all it does, but a subclass can use this to paint 
  54.      * things relative to the child.
  55.      *
  56.      * @param g the graphics context
  57.      * @param alloc the allocated region to paint into
  58.      * @param index the child index, >= 0 && < getViewCount()
  59.      */
  60.     protected void paintChild(Graphics g, Rectangle alloc, int index) {
  61.     View child = getView(index);
  62.     child.paint(g, alloc);
  63.     }
  64.  
  65.     /**
  66.      * Invalidates the layout and resizes the cache of requests/allocations.
  67.      *
  68.      * @param offset the starting offset into the child views >= 0
  69.      * @param length the number of existing views to replace >= 0
  70.      * @param elems the child views to insert
  71.      */
  72.     public void replace(int offset, int length, View[] elems) {
  73.     super.replace(offset, length, elems);
  74.  
  75.     // invalidate cache 
  76.     xOffsets = null;
  77.     xSpans = null;
  78.     xValid = false;
  79.     xAllocValid = false;
  80.     yOffsets = null;
  81.     ySpans = null;
  82.     yValid = false;
  83.     yAllocValid = false;
  84.     }
  85.  
  86.     // --- View methods ---------------------------------------------
  87.  
  88.     /**
  89.      * This is called by a child to indicated its 
  90.      * preferred span has changed.  This is implemented to
  91.      * throw away cached layout information so that new
  92.      * calculations will be done the next time the children
  93.      * need an allocation.
  94.      *
  95.      * @param child the child view
  96.      * @param width true if the width preference should change
  97.      * @param height true if the height preference should change
  98.      */
  99.     public void preferenceChanged(View child, boolean width, boolean height) {
  100.     if (width) {
  101.         xValid = false;
  102.         xAllocValid = false;
  103.     }
  104.     if (height) {
  105.         yValid = false;
  106.         yAllocValid = false;
  107.     }
  108.     super.preferenceChanged(child, width, height);
  109.     }
  110.  
  111.     /**
  112.      * Sets the size of the view.  If the size has changed, layout
  113.      * is redone.  The size is the full size of the view including
  114.      * the inset areas.
  115.      *
  116.      * @param width the width >= 0
  117.      * @param height the height >= 0
  118.      */
  119.     public void setSize(float width, float height) {
  120.     if (((int) width) != this.width) {
  121.         xAllocValid = false;
  122.     }
  123.     if (((int) height) != this.height) { 
  124.         yAllocValid = false;
  125.     }
  126.     if ((! xAllocValid) || (! yAllocValid)) {
  127.         this.width = (int) width;
  128.         this.height = (int) height;
  129.         layout((int) (this.width - getLeftInset() - getRightInset()), 
  130.            (int) (this.height - getTopInset() - getBottomInset()));
  131.     }
  132.     }
  133.  
  134.     /**
  135.      * Renders using the given rendering surface and area on that
  136.      * surface.
  137.      *
  138.      * @param g the rendering surface to use
  139.      * @param allocation the allocated region to render into
  140.      * @see View#paint
  141.      */
  142.     public void paint(Graphics g, Shape allocation) {
  143.     Rectangle alloc = allocation.getBounds();
  144.     setSize(alloc.width, alloc.height);
  145.     int n = getViewCount();
  146.     int x = alloc.x + getLeftInset();
  147.     int y = alloc.y + getTopInset();
  148.     Rectangle clip = g.getClipBounds();
  149.     for (int i = 0; i < n; i++) {
  150.         alloc.x = x + xOffsets[i];
  151.         alloc.y = y + yOffsets[i];
  152.         alloc.width = xSpans[i];
  153.         alloc.height = ySpans[i];
  154.         if (alloc.intersects(clip)) {
  155.         paintChild(g, alloc, i);
  156.         }
  157.     }
  158.     }
  159.  
  160.     /**
  161.      * Provides a mapping from the document model coordinate space
  162.      * to the coordinate space of the view mapped to it.  This makes
  163.      * sure the allocation is valid before letting the superclass
  164.      * do its thing.
  165.      *
  166.      * @param pos the position to convert >= 0
  167.      * @param a the allocated region to render into
  168.      * @return the bounding box of the given position
  169.      * @exception BadLocationException  if the given position does
  170.      *  not represent a valid location in the associated document
  171.      * @see View#modelToView
  172.      */
  173.     public Shape modelToView(int pos, Shape a) throws BadLocationException {
  174.     if (! isAllocationValid()) {
  175.         Rectangle alloc = a.getBounds();
  176.         setSize(alloc.width, alloc.height);
  177.     }
  178.     return super.modelToView(pos, a);
  179.     }
  180.  
  181.     /**
  182.      * Provides a mapping from the view coordinate space to the logical
  183.      * coordinate space of the model.
  184.      *
  185.      * @param x   x coordinate of the view location to convert >= 0
  186.      * @param y   y coordinate of the view location to convert >= 0
  187.      * @param a the allocated region to render into
  188.      * @return the location within the model that best represents the
  189.      *  given point in the view >= 0
  190.      * @see View#viewToModel
  191.      */
  192.     public int viewToModel(float x, float y, Shape a) {
  193.     if (! isAllocationValid()) {
  194.         Rectangle alloc = a.getBounds();
  195.         setSize(alloc.width, alloc.height);
  196.     }
  197.     return super.viewToModel(x, y, a);
  198.     }
  199.  
  200.     /**
  201.      * Determines the desired alignment for this view along an
  202.      * axis.  This is implemented to give the total alignment
  203.      * needed to position the children with the alignment points
  204.      * lined up along the axis orthoginal to the axis that is
  205.      * being tiled.  The axis being tiled will request to be
  206.      * centered (i.e. 0.5f).
  207.      *
  208.      * @param axis may be either View.X_AXIS or View.Y_AXIS
  209.      * @returns the desired alignment >= 0.0f && <= 1.0f.  This should
  210.      *   be a value between 0.0 and 1.0 where 0 indicates alignment at the
  211.      *   origin and 1.0 indicates alignment to the full span
  212.      *   away from the origin.  An alignment of 0.5 would be the
  213.      *   center of the view.
  214.      * @exception IllegalArgumentException for an invalid axis
  215.      */
  216.     public float getAlignment(int axis) {
  217.     checkRequests();
  218.     switch (axis) {
  219.     case View.X_AXIS:
  220.     case View.Y_AXIS:
  221.         return alignment[axis];
  222.     default:
  223.         throw new IllegalArgumentException("Invalid axis: " + axis);
  224.     }
  225.     }
  226.  
  227.     /**
  228.      * Determines the resizability of the view along the
  229.      * given axis.  A value of 0 or less is not resizable.
  230.      *
  231.      * @param axis may be either View.X_AXIS or View.Y_AXIS
  232.      * @return the resize weight
  233.      * @exception IllegalArgumentException for an invalid axis
  234.      */
  235.     public int getResizeWeight(int axis) {
  236.     checkRequests();
  237.     switch (axis) {
  238.     case View.X_AXIS:
  239.     case View.Y_AXIS:
  240.         return resizeWeight[axis];
  241.     default:
  242.         throw new IllegalArgumentException("Invalid axis: " + axis);
  243.     }
  244.     }
  245.  
  246.     /**
  247.      * Determines the preferred span for this view along an
  248.      * axis.
  249.      *
  250.      * @param axis may be either View.X_AXIS or View.Y_AXIS
  251.      * @returns  the span the view would like to be rendered into >= 0.
  252.      *           Typically the view is told to render into the span
  253.      *           that is returned, although there is no guarantee.  
  254.      *           The parent may choose to resize or break the view.
  255.      * @exception IllegalArgumentException for an invalid axis type
  256.      */
  257.     public float getPreferredSpan(int axis) {
  258.     checkRequests();
  259.     switch (axis) {
  260.     case View.X_AXIS:
  261.         return preferredSpan[axis] + getLeftInset() + getRightInset();
  262.     case View.Y_AXIS:
  263.         return preferredSpan[axis] + getTopInset() + getBottomInset();
  264.     default:
  265.         throw new IllegalArgumentException("Invalid axis: " + axis);
  266.     }
  267.     }
  268.  
  269.     /**
  270.      * Gives notification that something was inserted into the document
  271.      * in a location that this view is responsible for.
  272.      *
  273.      * @param e the change information from the associated document
  274.      * @param a the current allocation of the view
  275.      * @param f the factory to use to rebuild if the view has children
  276.      * @see View#insertUpdate
  277.      */
  278.     public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) {
  279.     Element elem = getElement();
  280.     DocumentEvent.ElementChange ec = e.getChange(elem);
  281.     if (ec != null) {
  282.         // the structure of this element changed.
  283.         Element[] removedElems = ec.getChildrenRemoved();
  284.         Element[] addedElems = ec.getChildrenAdded();
  285.         View[] added = new View[addedElems.length];
  286.         for (int i = 0; i < addedElems.length; i++) {
  287.         added[i] = f.create(addedElems[i]);
  288.         }
  289.         replace(ec.getIndex(), removedElems.length, added);
  290.  
  291.         // should damge a little more intelligently.
  292.         if (a != null) {
  293.         preferenceChanged(null, true, true);
  294.         getContainer().repaint();
  295.         }
  296.     }
  297.  
  298.     // find and forward if there is anything there to 
  299.     // forward to.  If children were removed then there was
  300.     // a replacement of the removal range and there is no
  301.     // need to forward.
  302.  
  303.     // PENDING(prinz) fixup DocumentEvent to provide more
  304.     // info so forwarding can be properly done.
  305.     Rectangle alloc = ((a != null) && isAllocationValid()) ? 
  306.         getInsideAllocation(a) : null;
  307.     int pos = e.getOffset();
  308.     View v = getViewAtPosition(pos, alloc);
  309.     if (v != null) {
  310.         v.insertUpdate(e, alloc, f);
  311.         if ((v.getStartOffset() == pos) && (pos > 0)) {
  312.         v = getViewAtPosition(pos-1, alloc);
  313.         v.insertUpdate(e, alloc, f);
  314.         }
  315.     }
  316.     }
  317.  
  318.     /**
  319.      * Gives notification that something was removed from the document
  320.      * in a location that this view is responsible for.
  321.      *
  322.      * @param e the change information from the associated document
  323.      * @param a the current allocation of the view
  324.      * @param f the factory to use to rebuild if the view has children
  325.      * @see View#removeUpdate
  326.      */
  327.     public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) {
  328.     Element elem = getElement();
  329.     DocumentEvent.ElementChange ec = e.getChange(elem);
  330.     boolean shouldForward = true;
  331.     if (ec != null) {
  332.         Element[] removedElems = ec.getChildrenRemoved();
  333.         Element[] addedElems = ec.getChildrenAdded();
  334.         View[] added = new View[addedElems.length];
  335.         for (int i = 0; i < addedElems.length; i++) {
  336.         added[i] = f.create(addedElems[i]);
  337.         }
  338.         replace(ec.getIndex(), removedElems.length, added);
  339.         if (added.length != 0) {
  340.         shouldForward = false;
  341.         }
  342.  
  343.         // should damge a little more intelligently.
  344.         if (a != null) {
  345.         preferenceChanged(null, true, true);
  346.         getContainer().repaint();
  347.         }
  348.     }
  349.  
  350.     // find and forward if there is anything there to 
  351.     // forward to.  If children were added then there was
  352.     // a replacement of the removal range and there is no
  353.     // need to forward.
  354.     if (shouldForward) {
  355.         Rectangle alloc = ((a != null) && isAllocationValid()) ? 
  356.         getInsideAllocation(a) : null;
  357.         int pos = e.getOffset();
  358.         View v = getViewAtPosition(pos, alloc);
  359.         if (v != null) {
  360.         v.removeUpdate(e, alloc, f);
  361.         }
  362.     }
  363.     }
  364.  
  365.     /**
  366.      * Gives notification from the document that attributes were changed
  367.      * in a location that this view is responsible for.
  368.      *
  369.      * @param e the change information from the associated document
  370.      * @param a the current allocation of the view
  371.      * @param f the factory to use to rebuild if the view has children
  372.      * @see View#changedUpdate
  373.      */
  374.     public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
  375.     Element elem = getElement();
  376.  
  377.         // forward
  378.     Rectangle alloc = ((a != null) && isAllocationValid()) ? 
  379.         getInsideAllocation(a) : null;
  380.     int x = 0;
  381.     int y = 0;
  382.     int width = 0;
  383.     int height = 0;
  384.     if (alloc != null) {
  385.         x = alloc.x;
  386.         y = alloc.y;
  387.         width = alloc.width;
  388.         height = alloc.height;
  389.     }
  390.     int index0 = elem.getElementIndex(e.getOffset());
  391.     int index1 = elem.getElementIndex(e.getOffset() + Math.max(e.getLength() - 1, 0));
  392.     for (int i = index0; i <= index1; i++) {
  393.         View v = getView(i);
  394.         if (alloc != null) {
  395.         alloc.x = x + xOffsets[i];
  396.         alloc.y = y + yOffsets[i];
  397.         alloc.width = xSpans[i];
  398.         alloc.height = ySpans[i];
  399.         }
  400.         v.changedUpdate(e, alloc, f);
  401.     }
  402.  
  403.     // replace children if necessary.
  404.     DocumentEvent.ElementChange ec = e.getChange(elem);
  405.     if (ec != null) {
  406.         Element[] removedElems = ec.getChildrenRemoved();
  407.         Element[] addedElems = ec.getChildrenAdded();
  408.         View[] added = new View[addedElems.length];
  409.         for (int i = 0; i < addedElems.length; i++) {
  410.         added[i] = f.create(addedElems[i]);
  411.         }
  412.         replace(ec.getIndex(), removedElems.length, added);
  413.     }
  414.     
  415.     if ((a != null) && ! isAllocationValid()) {
  416.         // size changed
  417.         Component c = getContainer();
  418.         c.repaint(x, y, width, height);
  419.     }
  420.     }
  421.  
  422.     // --- local methods ----------------------------------------------------
  423.  
  424.     /**
  425.      * Are the allocations for the children still
  426.      * valid?
  427.      *
  428.      * @return true if allocations still valid
  429.      */
  430.     protected boolean isAllocationValid() {
  431.     return (xAllocValid && yAllocValid);
  432.     }
  433.    
  434.     /**
  435.      * Determines if a point falls before an allocated region.
  436.      *
  437.      * @param x the X coordinate >= 0
  438.      * @param y the Y coordinate >= 0
  439.      * @param innerAlloc the allocated region.  This is the area
  440.      *   inside of the insets.
  441.      * @return true if the point lies before the region else false
  442.      */
  443.     protected boolean isBefore(int x, int y, Rectangle innerAlloc) {
  444.     if (axis == View.X_AXIS) {
  445.         return (x < innerAlloc.x);
  446.     } else {
  447.         return (y < innerAlloc.y);
  448.     }
  449.     }
  450.  
  451.     /**
  452.      * Determines if a point falls after an allocated region.
  453.      *
  454.      * @param x the X coordinate >= 0
  455.      * @param y the Y coordinate >= 0
  456.      * @param innerAlloc the allocated region.  This is the area
  457.      *   inside of the insets.
  458.      * @return true if the point lies after the region else false
  459.      */
  460.     protected boolean isAfter(int x, int y, Rectangle innerAlloc) {
  461.     if (axis == View.X_AXIS) {
  462.         return (x > (innerAlloc.width + innerAlloc.x));
  463.     } else {
  464.         return (y > (innerAlloc.height + innerAlloc.y));
  465.     }
  466.     }
  467.  
  468.     /**
  469.      * Fetches the child view at the given point.
  470.      *
  471.      * @param x the X coordinate >= 0
  472.      * @param y the Y coordinate >= 0
  473.      * @param alloc the parents inner allocation on entry, which should
  474.      *   be changed to the childs allocation on exit.
  475.      * @return the view
  476.      */
  477.     protected View getViewAtPoint(int x, int y, Rectangle alloc) {
  478.     int n = getViewCount();
  479.     if (axis == View.X_AXIS) {
  480.         if (x < (alloc.x + xOffsets[0])) {
  481.         childAllocation(0, alloc);
  482.         return getView(0);
  483.         }
  484.         for (int i = 0; i < n; i++) {
  485.         if (x < (alloc.x + xOffsets[i])) {
  486.             childAllocation(i - 1, alloc);
  487.             return getView(i - 1);
  488.         }
  489.         }
  490.         childAllocation(n - 1, alloc);
  491.         return getView(n - 1);
  492.     } else {
  493.         if (y < (alloc.y + yOffsets[0])) {
  494.         childAllocation(0, alloc);
  495.         return getView(0);
  496.         }
  497.         for (int i = 0; i < n; i++) {
  498.         if (y < (alloc.y + yOffsets[i])) {
  499.             childAllocation(i - 1, alloc);
  500.             return getView(i - 1);
  501.         }
  502.         }
  503.         childAllocation(n - 1, alloc);
  504.         return getView(n - 1);
  505.     }
  506.     }
  507.  
  508.     /**
  509.      * Allocates a region for a child view.  
  510.      *
  511.      * @param index the index of the child view to
  512.      *   allocate, >= 0 && < getViewCount()
  513.      * @param alloc the allocated region
  514.      */
  515.     protected void childAllocation(int index, Rectangle alloc) {
  516.     alloc.x += xOffsets[index];
  517.     alloc.y += yOffsets[index];
  518.     alloc.width = xSpans[index];
  519.     alloc.height = ySpans[index];
  520.     }
  521.  
  522.     /**
  523.      * Performs layout of the children.  The size is the
  524.      * area inside of the insets.
  525.      *
  526.      * @param width the width >= 0
  527.      * @param height the height >= 0
  528.      */
  529.     protected void layout(int width, int height) {
  530.     checkRequests();
  531.  
  532.     // rebuild the allocation arrays if they've been removed
  533.     // due to a change in child count.
  534.     if (xSpans == null) {
  535.         int n = getViewCount();
  536.         xSpans = new int[n];
  537.         ySpans = new int[n];
  538.         xOffsets = new int[n];
  539.         yOffsets = new int[n];
  540.     }
  541.     if (axis == X_AXIS) {
  542.         if (! xAllocValid) {
  543.         calculateTiledPositions(width, View.X_AXIS);
  544.         }
  545.         if (! yAllocValid) {
  546.         calculateAlignedPositions(height, View.Y_AXIS);
  547.         }
  548.     } else {
  549.         if (! xAllocValid) {
  550.         calculateAlignedPositions(width, View.X_AXIS);
  551.         }
  552.         if (! yAllocValid) {
  553.         calculateTiledPositions(height, View.Y_AXIS);
  554.         }
  555.     }
  556.     xAllocValid = true;
  557.     yAllocValid = true;
  558.  
  559.     // flush changes to the children
  560.     int n = getViewCount();
  561.     for (int i = 0; i < n; i++) {
  562.         View v = getView(i);
  563.         v.setSize((float) xSpans[i], (float) ySpans[i]);
  564.     }
  565.     }
  566.  
  567.     /**
  568.      * The current width of the box.  This is the width that
  569.      * it was last allocated.
  570.      */
  571.     public final int getWidth() {
  572.     return width;
  573.     }
  574.  
  575.     /**
  576.      * The current height of the box.  This is the height that
  577.      * it was last allocated.
  578.      */
  579.     public final int getHeight() {
  580.     return height;
  581.     }
  582.  
  583.     /**
  584.      * Checks the request cache and update if needed.
  585.      */
  586.     void checkRequests() {
  587.     if (axis == X_AXIS) {
  588.         if (! xValid) {
  589.         calculateTiledSizeRequirements(View.X_AXIS);
  590.         }
  591.         if (! yValid) {
  592.         calculateAlignedSizeRequirements(View.Y_AXIS);
  593.         }
  594.     } else {
  595.         if (! xValid) {
  596.         calculateAlignedSizeRequirements(View.X_AXIS);
  597.         }
  598.         if (! yValid) {
  599.         calculateTiledSizeRequirements(View.Y_AXIS);
  600.         }
  601.     }
  602.     yValid = true;
  603.     xValid = true;
  604.     }
  605.  
  606.     /**
  607.      * Determines the total space necessary to
  608.      * place a set of components end-to-end.  
  609.      */
  610.     void calculateTiledSizeRequirements(int axis) {
  611.     alignment[axis] = 0.5f;
  612.     preferredSpan[axis] = 0;
  613.     resizeWeight[axis] = 0;
  614.     int n = getViewCount();
  615.     for (int i = 0; i < n; i++) {
  616.         View v = getView(i);
  617.         preferredSpan[axis] += v.getPreferredSpan(axis);
  618.         resizeWeight[axis] += v.getResizeWeight(axis);
  619.     }
  620.     }
  621.  
  622.     /**
  623.      * Determines the total space necessary to
  624.      * align a set of views along the given axis.
  625.      */
  626.     void calculateAlignedSizeRequirements(int axis) {
  627.  
  628.     int totalAbove = 0;
  629.     int totalBelow = 0;
  630.     int n = getViewCount();
  631.     for (int i = 0; i < n; i++) {
  632.         View v = getView(i);
  633.         int span = (int) v.getPreferredSpan(axis);
  634.         int below = (int) (v.getAlignment(axis) * span);
  635.         int above = span - below;
  636.         totalAbove = Math.max(above, totalAbove);
  637.         totalBelow = Math.max(below, totalBelow);
  638.         resizeWeight[axis] += v.getResizeWeight(axis);
  639.     }
  640.     preferredSpan[axis] = (int) (totalAbove + totalBelow);
  641.     alignment[axis] = 0.5f;
  642.     if (preferredSpan[axis] > 0) {
  643.         alignment[axis] = (float) totalBelow / preferredSpan[axis];
  644.     }
  645.     }
  646.  
  647.     void calculateAlignedPositions(int allocated, int axis) {
  648.     int[] offsets = (axis == View.X_AXIS) ? xOffsets : yOffsets;
  649.     int[] spans = (axis == View.X_AXIS) ? xSpans : ySpans;
  650.  
  651.     int totalBelow = (int) (allocated * alignment[axis]);
  652.     int totalAbove = allocated - totalBelow;
  653.     int n = getViewCount();
  654.     for (int i = 0; i < n; i++) {
  655.         View v = getView(i);
  656.         float align = v.getAlignment(axis);
  657.         int span = (int) v.getPreferredSpan(axis);
  658.         int below = (int) (span * align);
  659.         int above = span - below;
  660.         if (v.getResizeWeight(axis) > 0) {
  661.         below = totalBelow;
  662.         above = totalAbove;
  663.         }
  664.  
  665.         offsets[i] = totalBelow - below;
  666.         spans[i] = (int) (below + above);
  667.     }
  668.     }
  669.  
  670.     void calculateTiledPositions(int allocated, int axis) {
  671.     int[] offsets = (axis == View.X_AXIS) ? xOffsets : yOffsets;
  672.     int[] spans = (axis == View.X_AXIS) ? xSpans : ySpans;
  673.     int totalPlay = allocated - preferredSpan[axis];
  674.     int totalWeight = resizeWeight[axis];
  675.     int totalOffset = 0;
  676.     int n = getViewCount();
  677.     for (int i = 0; i < n; i++) {
  678.         View v = getView(i);
  679.         offsets[i] = totalOffset;
  680.         int span = (int) v.getPreferredSpan(axis);
  681.         int weight = v.getResizeWeight(axis);
  682.         if ((weight != 0) && (totalWeight != 0)) {
  683.         // adjust the span
  684.         float factor = weight / totalWeight;
  685.         span += totalPlay * factor;
  686.         }
  687.         spans[i] = span;
  688.         totalOffset += span;
  689.     }
  690.     }
  691.  
  692.     // --- variables ------------------------------------------------
  693.  
  694.     int axis;
  695.     int width;
  696.     int height;
  697.  
  698.     /**
  699.      * Request cache
  700.      */
  701.     boolean xValid;
  702.     boolean yValid;
  703.     int[] preferredSpan = new int[2];
  704.     int[] resizeWeight = new int[2];
  705.     float[] alignment = new float[2];
  706.  
  707.     /**
  708.      * Allocation cache
  709.      */
  710.     boolean xAllocValid;
  711.     int[] xOffsets;
  712.     int[] xSpans;
  713.     boolean yAllocValid;
  714.     int[] yOffsets;
  715.     int[] ySpans;
  716. }
  717.